package model.quadtree;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.List;

/**
 * The node class, used for the <code>QuadTree</code>. It holds the
 * link for each 4 children and the parent, his <code>Type</code> and
 * the 2 vertex that defines the cell. Another two auxiliary attributes
 * are used to hold the ID and the state for <code>BLACK</code> types.
 * 
 * To define a cell, the 2 vertex must be set like below:
 * 
 * 		 ___________
 * 		|		   vert1
 * 		|			|
 * 		|			|
 * 		|			|
 * 	  vert2_________|
 * 
 * The type specifies wheter the node is <code>WHITE</code>, <code>BLACK</code>
 * or <code>GREY</code>, when it is empty, containing or intersecting the
 * obstacles, respectly.
 * 
 * @author 	Jody Matos, João Carlos
 * @version 1.0
 * @since	01/18/2012
 * @see QuadTree and Type
 * 
 * <dt><b>History:</b></dt>
 * 	<dd>1.0: Initial implementation.</dd>
 */
public class Node {
	public static int 	idGenerator;
	private int			id;
	protected Type 		type;
	private Node		parent;
	private Node[]		child;
	protected Point		vert1, vert2, center;
	protected boolean	done;
	protected boolean	leaf;

	public boolean isLeaf() {
		return leaf;
	}

	public void setLeaf(boolean leaf) {
		this.leaf = leaf;
	}

	/**
	 * Constructs an instance of <code>Node</code>, specifying his type,
	 * using the <code>static</code> params of <code>Type</code>, like
	 * <code>WHITE</code>, <code>BLACK</code> or <code>GREY</code>, to
	 * indicates his state: empty, containing or intersecting the obstacles,
	 * respectly.
	 * 
	 * @param type	<code>Type</code>, defining his state.
	 * @param vert1 <code>Point</code>, specifying the top-right vertex.
	 * @param vert2 <code>Point</code>, specifying the bottom-left vertex.
	 * @param parent <code>Node</code>, linking for his parent.
	 */
	public Node(Type type, Point vert1, Point vert2, Node parent){
		this.id = idGenerator++;
		this.type = type;
		this.vert1 = vert1;
		this.vert2 = vert2;
		this.parent = parent;
		this.done = false;
		this.leaf = true;
		this.center = new Point((vert1.x+vert2.x)/2, (vert1.y+vert2.y)/2);
	}

	/**
	 * Constructs an instance of <code>Node</code>, specifying his type,
	 * using the <code>static</code> params of <code>Type</code>, like
	 * <code>WHITE</code>, <code>BLACK</code> or <code>GREY</code>, to
	 * indicates his state: empty, containing or intersecting the obstacles,
	 * respectly. Used when the node is the tree's root and haven't a parent. 
	 * 
	 * @param type	<code>Type</code>, defining his state.
	 * @param vert1 <code>Point</code>, specifying the top-right vertex.
	 * @param vert2 <code>Point</code>, specifying the bottom-left vertex.
	 */
	public Node(Type type, Point vert1, Point vert2) {
		this(type, vert1, vert2, null);
		this.leaf = false;
	}

	public Point getCenter() {
		return center;
	}

	public void setCenter(Point center) {
		this.center = center;
	}

	/**
	 * Make instances for the 4 children of a <code>QuadTree</code> node. The
	 * 4 inner cells takes the reference of half horizontal and vertical points
	 * of the current node, which should be his parent. The child orientation
	 * follows the Z orientaion, like below:
	 * 
	 * 		 _______________________
	 * 		|			|			|
	 * 		|			|			|
	 * 		|	C[0]	|	C[1]	|
	 * 		|			|			|
	 * 		|-----------|-----------|
	 * 		|			|			|
	 * 		|	C[2]	|	C[3]	|
	 * 		|			|			|
	 * 		|___________|___________|
	 * 
	 */
	public void makeChildren(){
		child = new Node[4];
		int x1 = this.vert1.x, y1 = this.vert1.y;
		int x2 = this.vert2.x, y2 = this.vert2.y;
		int xMiddle = (x1+x2)/2, y2Half = (y1+y2)/2;

		Point p01 = new Point(xMiddle, y1);
		Point p02 = new Point(x2, y2Half);
		Point p11 = this.vert1;
		Point p12 = new Point(xMiddle, y2Half);
		Point p21 = p12;
		Point p22 = this.vert2;
		Point p31 = new Point(x1, y2Half);
		Point p32 = new Point(xMiddle, y2);

		child[0] = new Node(Type.WHITE, p01, p02, this);
		child[1] = new Node(Type.WHITE, p11, p12, this);
		child[2] = new Node(Type.WHITE, p21, p22, this);
		child[3] = new Node(Type.WHITE, p31, p32, this);
		
		this.leaf = false;
		this.type = Type.GREY;
	}

	/**
	 * Classify the node, specifying his type based on the arena
	 * obstacles. When a cell contains one obstacle, or even it
	 * is full by him, it must be <code>Type.BLACK<code>; for 
	 * cases when a cell simply intersects an obstacle, it must be
	 * <code>Type.GREY</code>; finally, when it is empty, it must be
	 * <code>Type.WHITE<code>.
	 * 
	 * @param obstacles <code>List</code> of <code>Rectangles</code>, specifying
	 * the arena obstacles.
	 */
	public void classifyNode(List<Rectangle> obstacles){
		if(this.type!=Type.GREY){
			int x = vert2.x, y = vert1.y, width = vert1.x-vert2.x, height = vert2.y-vert1.y;
			Rectangle cell = new Rectangle(x, y, width, height);
			for(Rectangle obstacle : obstacles){
				if(obstacle.contains(cell) || cell.contains(obstacle)){
					if(type==Type.BLACK && !done)
						this.type = Type.GREY;
					else{
						this.type = Type.BLACK;
					}
				} else if(obstacle.intersects(x, y, width, height)){
					this.type = Type.GREY;
				}
			}
			done=true;
		}
	}

	/**
	 * Returns the node ID.
	 * 
	 * @return <code>int</code> ID of the node.
	 */
	public int getId() {
		return id;
	}

	/**
	 * Set the node ID.
	 * 
	 * @param id <code>int</code> ID of the node.
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * Returns the node type.
	 * 
	 * @return <Type> type of the node.
	 */
	public Type getType() {
		return type;
	}

	/**
	 * Set the node type.
	 * 
	 * @param type <Type> type of the node.
	 */
	public void setType(Type type) {
		this.type = type;
	}

	/**
	 * Returns the node parent.
	 * 
	 * @return <code>Node</code> parent of the node.
	 */
	public Node getParent() {
		return parent;
	}

	/**
	 * Set the node parent.
	 * 
	 * @param parent <code>Node</code> parent of the node.
	 */
	public void setParent(Node parent) {
		this.parent = parent;
	}

	/**
	 * Returns the node children, like Z orientation.
	 * 
	 * 		 _______________________
	 * 		|			|			|
	 * 		|			|			|
	 * 		|	C[0]	|	C[1]	|
	 * 		|			|			|
	 * 		|-----------|-----------|
	 * 		|			|			|
	 * 		|	C[2]	|	C[3]	|
	 * 		|			|			|
	 * 		|___________|___________|
	 *  
	 * @return <code>Node[]</code> children of the node.
	 */
	public Node[] getChild() {
		return child;
	}

	/**
	 * Set the node children, like Z orientation.
	 * 
	 * 		 _______________________
	 * 		|			|			|
	 * 		|			|			|
	 * 		|	C[0]	|	C[1]	|
	 * 		|			|			|
	 * 		|-----------|-----------|
	 * 		|			|			|
	 * 		|	C[2]	|	C[3]	|
	 * 		|			|			|
	 * 		|___________|___________|
	 * 
	 * @param child <code>Node[]</code> children of the node.
	 */
	public void setChild(Node[] child) {
		this.child = child;
	}

	/**
	 * Returns the top-right cell's vertex.
	 * 
	 * @return <code>Point</code> top-left vertex of the cell.
	 */
	public Point getVert1() {
		return vert1;
	}

	/**
	 * Set the top-right cell's vertex.
	 * 
	 * @param vert1 <code>Point</code> top-right vertex of the cell.
	 */
	public void setVert1(Point vert1) {
		this.vert1 = vert1;
	}

	/**
	 * Returns the bottom-left cell's vertex.
	 * 
	 * @return <code>Point</code> bottom-left vertex of the cell.
	 */
	public Point getVert2() {
		return vert2;
	}

	/**
	 * Set the bottom-left cell's vertex.
	 * 
	 * @param vert2 <code>Point</code> bottom-left vertex of the cell.
	 */
	public void setVert2(Point vert2) {
		this.vert2 = vert2;
	}
}
